/*
 * =====================================================================================
 *
 *       Filename:  exit.c
 *
 *    Description: exit function 
 *
 *        Created:  2011年03月15日 20时18分34秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  lonelydragon1988@gmail.com 
 *        Company:  
 *
 * =====================================================================================
 */
#include <sched.h>
#include <signal.h>
#include <segment.h>
#include <tty.h>
#include <kernel.h>

#include <errno.h>
#include <errno.h>


int sys_pause();
int sys_close(int fd);


void release(struct task_struct *p)
{
	int i;
	if(!p)
		return;
	for(i=1;i<NR_TASKS;i++)
	{
		if(task[i]==p)
		{
			task[i]=NULL;
			free_page((long)p);
			schedule();
			return;
		}
	}
	print("wrong,try to release not exit task \n");
}

//priv 是强制发送信号的标志
static inline int send_sig(long sig,struct task_struct *p,int priv)
{
	if(sig>32 || sig<1 || !p)
		return -EINVAL;
	//判定强制标志，判断是否为本进程 判断是否为超级用户
	if(priv ||(current->euid==p->euid)||suser())
		p->signal|=(1<<(sig-1));
	else
		return -EPERM;
	return 0;
}

static void kill_session(void)
{
	struct task_struct **p=NR_TASKS+task;
	while(--p>=&FIRST_TASK)
	{
		if(*p && (*p)->session==current->session)
			(*p)->signal|=(1<<(SIGHUP-1));
	}
}


/*
 * 	XXX 	kill task
 */

int sys_kill(int pid,int sig)
{
	struct task_struct **p=NR_TASKS+task;
	int err,retval=0;
	//pid=0 信号发送给改进程组的所有成员
	if(!pid)
	{
		while(--p>&FIRST_TASK)
		{
			if(*p && (*p)->pgrp==current->pid)
				if(err=send_sig(sig,*p,1))
					retval=err;
		}
	}
	//pid>0 将信号量发送给该信号的进程
	else if(pid>0)
	{
		while(--p>&FIRST_TASK)
		{
			if(*p && (*p)->pid==current->pid)
				if(err=send_sig(sig,*p,0))
					retval=err;
		}
	}
	//pid=-1 将信号量发送给除第一个进程外的所有进程
	else if(pid==-1)
		while(--p>&FIRST_TASK)
		if(err=send_sig(sig,*p,0))
			retval=err;
	//pid<0时 将信号量发送给进程组为-pid的所有进程
	else 
		wihle(--p>&FIRST_TASK)
		{
			if(*p && (*p)->pgrp == -pid)
				if(err=send_sig(sig,*p,0))
					retval=err;
		}
	return retval;
}

static void tell_father(int pid)
{
	int i;
	if(pid)
	{
		for(i=0;i<NR_TASKS;i++)
		{
			if(!task[i])
				continue;
			if(task[i]->pid!=pid)
				continue;
			task[i]->signal|=(1<<(SIGCHLD-1));
			return;
		}
	}
	print("no father \n");
	release(current);
}

// XXX 最重要的函数，但是不是很明白
int do_exit(long code)
{
	int i;
	/*
	 * free 着两个地址的意义何在？
	 */
	free_page_tables(get_base(current->ldt[1]),get_limit(0x0f));
	free_page_tables(get_base(current-<ldt[2]),get_limit(0x17));
	for(i=0;i<NR_TASKS;i++)
	{
		if(task[i]&& task[i]->father==current->pid)
		{
			task[i]->father=1;
			if(task[i]->state==TASK_ZOMBIE)
				send_sig(SIGCHLD,task[1],0);//这个函数原来是这么用的。
		}
	}
	for(i=0;i<NR_OPEN;i++)
		if(current->flip[i])
			sys_close(i);
	//对当前进程的工作目录 pwd 和根目录 root以及执行文件的i节点进行同步操作。
	iput(current->pwd);
	current->pwd=NULL;
	iput(current->root);
	current->root=NULL;
	iput(current->executable);
	current->executable=NULL;
	if(current->leader && current->tty>=0)
		tty_table[current->tty].pgrp=0;
	if(current->leader)
		kill_session();
	current->state=TASK_ZOMBIE;
	current->exit_code=code; //这个code 是从什么地方定义的呢？
	tell_father(current->father);
	schedule();
	return (-1);
}

int sys_exit(int error_code)
{
	return do_exit((error_code&0xff)<<8); //这个&0xff根本没有什么用处麻，保存低八位的信息根本不用在处理了。
}


int sys_waitpid(pid_t pid,unsigned long *stat_addr,int option)
{
	int flag,code;
	struct task_struct **p;
	verify_area(stat_addr,4);
repeat:
	flag=0;
	for(p=&FIRST_TASK;p<&LAST_TASK;p++)
	{
		if(!*p || *p==current)
			continue;
		if((*p)->father!=current->pid)
			continue;
		if(pid>0)
		{
			if((*p)->pid!=pid)
				continue;
		}
		else if(!pid){
			if((*p)->pgrp!=current->pgrp)
				continue;
		}
		else if(pid!=-1)
		{
			if((*p)->pgrp!=-pid)
				continue;
		}
		switch((*p)->state)
		{
			case TASK_STOPPED:
				if(!(option&WUNTRACED)) //这个是什么意思？
					continue;
				put_fs_long(0x7f,stat_addr);
				return (*p)->pid;
			case TASK_ZOMBIE:
				current->cutime+=(*p)->cutime;
				current->cstime+=(*p)->cstime;
				flag=(*p)->pid;
				code=(*p)->exit_code;
				release(*p);
				put_fs_long(code,stat_addr);
				return flag;
			default:
				flag=1;
				continue;
		}
	}
	if(flag)
	{
		if(option&WUNTRACED)  //WUNTRACED是什么东西和意思阿?
			return 0;
		current->state=TASK_INTERRUPTIBLE;
		schedule();
		if(!(current->signal&=~(1<<(SIGCHLD-1))))
			goto repeat;
		else
			return -EINTR;
	}
	return -ECHILD;
}
